package com.mikelouis.test.scala.impatient.chapter12_highorder_function

/**
 * Created by yuazhu on 4/23/2015.
 */
object Chapter12 {
  // 1
  def values(fun: (Int) => Int, low: Int, hight: Int) = for (i <- low to hight) yield (i, fun(i))

  // 2
  def max(a: Seq[Int]) = a.reduceLeft((x, y) => if (x > y) x else y)

  // 3
  def fact(n: Int) = if (n < 1) 1 else (2 to n).reduceLeft(_ * _)

  // 4
  def fact2(n: Int) = (1 to n).foldLeft(1)(_ * _)

  // 5
  def largest(fun: (Int) => Int, inputs: Seq[Int]) = fun(inputs.maxBy(fun))

  def largest2(fun: (Int) => Int, inputs: Seq[Int]) = max(inputs.map({ x => 10 * x - x * x}))

  // 6
  def largestAt(fun: (Int) => Int, inputs: Seq[Int]) = inputs.maxBy(fun)

  // 7
  def adjustToPair[A, B, C](fun: (A, B) => C)(tupleList: Seq[(A, B)]): Seq[C] = tupleList.map((x: (A, B)) => fun(x._1, x._2))

  // 8
  def areStringLengthCorresponding(strings: Seq[String], lengths: Seq[Int]) =
    strings.corresponds(lengths)(_.length == _)

  // 9
  def correspondsWithoutCurrying[A, B](one: Seq[A], another: Seq[B], fun: (A, B) => Boolean): Boolean = adjustToPair(fun)(one zip another).reduceLeft(_ && _)

  def correspondsWithCurrying[A, B](fun: (A, B) => Boolean)(one: Seq[A], another: Seq[B]): Boolean = adjustToPair(fun)(one zip another).reduceLeft(_ && _)

  // 10
  def unless(condition: Boolean)(statement: => Unit): Unit = if (!condition) statement

  def main(args: Array[String]) {
    println(values(x => x * x, -5, 5))

    println(max(List(1, 2, 3, 4, 5)))

    println(fact(5))
    println(fact(-1))

    println(fact2(5))
    println(fact2(-1))

    println(largest(x => 10 * x - x * x, 1 to 10))
    println(largest2(x => 10 * x - x * x, 1 to 10))

    println(largestAt(x => 10 * x - x * x, 1 to 10))

    println(adjustToPair[Int, Int, Int](_ * _)(List((6, 7), (5, 6))))
    println(adjustToPair[Int, Int, Int](_ + _)(List((6, 7), (5, 6))))
    println(adjustToPair[Int, Int, Int](_ * _)((1 to 10) zip (11 to 20)))

    println(areStringLengthCorresponding(List("a", "bc", "def"), List(1, 2, 3)))
    println(areStringLengthCorresponding(List("a", "bc", "def"), List(1, 2, 5)))

    println(correspondsWithoutCurrying(List("a", "bc", "def"), List(1, 2, 3), { (x: String, y: Int) => x.length == y}))
    println(correspondsWithoutCurrying[String, Int](List("a", "bc", "def"), List(1, 2, 5), {
      _.length == _
    }))

    println(correspondsWithCurrying[String, Int]({
      _.length == _
    })(List("a", "bc", "def"), List(1, 2, 3)))
    println(correspondsWithCurrying((x: String, y: Int) => x.length == y)(List("a", "bc", "def"), List(1, 2, 5)))

    unless(false) {
      println("unless condition is true")
    }
  }

}
